home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 24
/
Amiga Format AFCD24 (Feb 1998, Issue 108).iso
/
-in_the_mag-
/
emulation
/
amiga
/
uae-0.7.0b2
/
src
/
od-win32
/
posixemu.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-20
|
14KB
|
646 lines
/*
* UAE - The Un*x Amiga Emulator
*
* Win32 interface
*
* Copyright 1997 Mathias Ortmann
*/
#ifdef __GNUC__
#define __int64 long long
#include "machdep/winstuff.h"
#else
#include <windows.h>
#include <ddraw.h>
#include <stdlib.h>
#include <stdarg.h>
#include <commctrl.h>
#include <commdlg.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <io.h>
#endif
#include "config.h"
#include "sysconfig.h"
#include "sysdeps.h"
#include "options.h"
#include "memory.h"
#include "osdep/win32.h"
/* stdioemu, posixemu, mallocemu, and various file system helper routines */
static DWORD lasterror;
static int isillegal (unsigned char *str)
{
unsigned char a = *str, b = str[1], c = str[2];
if (a >= 'a' && a <= 'z')
a &= ~' ';
if (b >= 'a' && b <= 'z')
b &= ~' ';
if (c >= 'a' && c <= 'z')
c &= ~' ';
return (a == 'A' && b == 'U' && c == 'X' ||
a == 'C' && b == 'O' && c == 'N' ||
a == 'P' && b == 'R' && c == 'N' ||
a == 'N' && b == 'U' && c == 'L');
}
static int checkspace (char *str, char s, char d)
{
char *ptr = str;
while (*ptr && *ptr == s)
ptr++;
if (!*ptr || *ptr == '/' || *ptr == '\\') {
while (str < ptr)
*(str++) = d;
return 0;
}
return 1;
}
/* This is sick and incomplete... in the meantime, I have discovered six new illegal file name formats
* M$ sucks! */
void fname_atow (char *src, char *dst, int size)
{
char *lastslash = dst, *strt = dst;
int i, j;
while (size-- > 0) {
if (!(*dst = *src++))
break;
if (*dst == '~' || *dst == '|' || *dst == '*' || *dst == '?') {
if (size > 2) {
sprintf (dst, "~%02x", *dst);
size -= 2;
dst += 2;
}
} else if (*dst == '/') {
if (checkspace (lastslash, ' ', 0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash)) {
i = dst - lastslash - 3;
dst++;
for (j = i + 1; j--; dst--)
*dst = dst[-1];
*(dst++) = 0xa0;
dst += i;
size--;
} else if (*lastslash == '.' && (dst - lastslash == 1 || lastslash[1] == '.' && dst - lastslash == 2) && size) {
*(dst++) = 0xa0;
size--;
}
*dst = '\\';
lastslash = dst + 1;
}
dst++;
}
if (checkspace (lastslash, ' ', 0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash) && size > 1) {
i = dst - lastslash - 3;
dst++;
for (j = i + 1; j--; dst--)
*dst = dst[-1];
*(dst++) = 0xa0;
} else if (!strcmp (lastslash, ".") || !strcmp (lastslash, ".."))
strcat (lastslash, "\xa0");
}
int getdiskfreespace (char *name, int *f_blocks, int *f_bavail, int *f_bsize)
{
char buf1[1024];
char buf2[1024];
DWORD SectorsPerCluster;
DWORD BytesPerSector;
DWORD NumberOfFreeClusters;
DWORD TotalNumberOfClusters;
fname_atow (name, buf1, sizeof buf1);
GetFullPathName (buf1, sizeof buf2, buf2, NULL);
buf2[3] = 0;
if (!GetDiskFreeSpace (buf2, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters)) {
lasterror = GetLastError ();
return FALSE;
}
*f_blocks = TotalNumberOfClusters;
*f_bavail = NumberOfFreeClusters;
*f_bsize = SectorsPerCluster * BytesPerSector;
return TRUE;
}
/* Translate lasterror to valid AmigaDOS error code
* The mapping is probably not 100% correct yet */
long dos_errno (void)
{
int i;
static DWORD errtbl[][2] =
{
{ERROR_FILE_NOT_FOUND, 205}, /* 2 */
{ERROR_PATH_NOT_FOUND, 205}, /* 3 */
{ERROR_SHARING_VIOLATION, 202},
{ERROR_ACCESS_DENIED, 223}, /* 5 */
{ERROR_ARENA_TRASHED, 103}, /* 7 */
{ERROR_NOT_ENOUGH_MEMORY, 103}, /* 8 */
{ERROR_INVALID_BLOCK, 219}, /* 9 */
{ERROR_INVALID_DRIVE, 204}, /* 15 */
{ERROR_CURRENT_DIRECTORY, 214}, /* 16 */
{ERROR_NO_MORE_FILES, 232}, /* 18 */
{ERROR_LOCK_VIOLATION, 214}, /* 33 */
{ERROR_BAD_NETPATH, 204}, /* 53 */
{ERROR_NETWORK_ACCESS_DENIED, 214}, /* 65 */
{ERROR_BAD_NET_NAME, 204}, /* 67 */
{ERROR_FILE_EXISTS, 203}, /* 80 */
{ERROR_CANNOT_MAKE, 214}, /* 82 */
{ERROR_FAIL_I24, 223}, /* 83 */
{ERROR_DRIVE_LOCKED, 202}, /* 108 */
{ERROR_DISK_FULL, 221}, /* 112 */
{ERROR_NEGATIVE_SEEK, 219}, /* 131 */
{ERROR_SEEK_ON_DEVICE, 219}, /* 132 */
{ERROR_DIR_NOT_EMPTY, 216}, /* 145 */
{ERROR_ALREADY_EXISTS, 203}, /* 183 */
{ERROR_FILENAME_EXCED_RANGE, 205}, /* 206 */
{ERROR_NOT_ENOUGH_QUOTA, 221}, /* 1816 */
{ERROR_DIRECTORY, 212}};
for (i = sizeof (errtbl) / sizeof (errtbl[0]); i--;) {
if (errtbl[i][0] == lasterror)
return errtbl[i][1];
}
return 236;
}
static DWORD getattr (char *name, LPFILETIME lpft, size_t * size)
{
HANDLE hFind;
WIN32_FIND_DATA fd;
if ((hFind = FindFirstFile (name, &fd)) == INVALID_HANDLE_VALUE) {
lasterror = GetLastError ();
fd.dwFileAttributes = GetFileAttributes (name);
return fd.dwFileAttributes;
}
FindClose (hFind);
if (lpft)
*lpft = fd.ftLastWriteTime;
if (size)
*size = fd.nFileSizeLow;
return fd.dwFileAttributes;
}
int posixemu_access (char *name, int mode)
{
DWORD attr;
char buf[1024];
fname_atow (name, buf, sizeof buf - 4);
if ((attr = getattr (buf, NULL, NULL)) == ~0)
return -1;
if (attr & FILE_ATTRIBUTE_READONLY && (mode & 4)) {
lasterror = ERROR_ACCESS_DENIED;
return -1;
} else
return 0;
}
int posixemu_open (char *name, int oflag, int dummy)
{
DWORD fileaccess;
DWORD filecreate;
char buf[1024];
HANDLE hFile;
switch (oflag & (O_RDONLY | O_WRONLY | O_RDWR)) {
case O_RDONLY:
fileaccess = GENERIC_READ;
break;
case O_WRONLY:
fileaccess = GENERIC_WRITE;
break;
case O_RDWR:
fileaccess = GENERIC_READ | GENERIC_WRITE;
break;
default:
return -1;
}
switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
case 0:
case O_EXCL:
filecreate = OPEN_EXISTING;
break;
case O_CREAT:
filecreate = OPEN_ALWAYS;
break;
case O_CREAT | O_EXCL:
case O_CREAT | O_TRUNC | O_EXCL:
filecreate = CREATE_NEW;
break;
case O_TRUNC:
case O_TRUNC | O_EXCL:
filecreate = TRUNCATE_EXISTING;
break;
case O_CREAT | O_TRUNC:
filecreate = CREATE_ALWAYS;
break;
}
fname_atow (name, buf, sizeof buf);
if ((hFile = CreateFile (buf,
fileaccess,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
filecreate,
FILE_ATTRIBUTE_NORMAL,
NULL)) == INVALID_HANDLE_VALUE)
lasterror = GetLastError ();
return (int) hFile;
}
void posixemu_close (int hFile)
{
CloseHandle ((HANDLE) hFile);
}
int w32fopendel (char *name, char *mode, int delflag)
{
HANDLE hFile;
hFile = CreateFile (name,
mode[1] == '+' ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
delflag ? FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE : FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
lasterror = GetLastError ();
hFile = 0;
}
return (int) hFile;
}
int stdioemu_fclose (FILE * fd)
{
if (fd)
CloseHandle ((HANDLE) fd);
return 0;
}
void *mallocemu_malloc (int size)
{
return GlobalAlloc (GPTR, size);
}
void mallocemu_free (void *ptr)
{
GlobalFree (ptr);
}
static int hextol (char a)
{
if (a >= '0' && a <= '9')
return a - '0';
if (a >= 'a' && a <= 'f')
return a - 'a' + 10;
if (a >= 'A' && a <= 'F')
return a - 'A' + 10;
return 2;
}
/* Win32 file name restrictions suck... */
void fname_wtoa (unsigned char *ptr)
{
unsigned char *lastslash = ptr;
while (*ptr) {
if (*ptr == '~') {
*ptr = hextol (ptr[1]) * 16 + hextol (ptr[2]);
strcpy (ptr + 1, ptr + 3);
} else if (*ptr == '\\') {
if (checkspace (lastslash, ' ', 0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash)) {
ptr--;
strcpy (lastslash + 3, lastslash + 4);
}
*ptr = '/';
lastslash = ptr + 1;
}
ptr++;
}
if (checkspace (lastslash, ' ', 0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash))
strcpy (lastslash + 3, lastslash + 4);
}
DIR {
WIN32_FIND_DATA finddata;
HANDLE hDir;
int getnext;
};
DIR *opendir (char *path)
{
char buf[1024];
DIR *dir;
if (!(dir = (DIR *) GlobalAlloc (GPTR, sizeof (DIR)))) {
lasterror = GetLastError ();
return 0;
}
fname_atow (path, buf, sizeof buf - 4);
strcat (buf, "\\*");
if ((dir->hDir = FindFirstFile (buf, &dir->finddata)) == INVALID_HANDLE_VALUE) {
lasterror = GetLastError ();
GlobalFree (dir);
return 0;
}
return dir;
}
struct dirent *readdir (DIR * dir)
{
if (dir->getnext) {
if (!FindNextFile (dir->hDir, &dir->finddata)) {
lasterror = GetLastError ();
return 0;
}
}
dir->getnext = TRUE;
fname_wtoa (dir->finddata.cFileName);
return (struct dirent *) dir->finddata.cFileName;
}
void closedir (DIR * dir)
{
FindClose (dir->hDir);
GlobalFree (dir);
}
int setfiletime (char *name, unsigned int days, int minute, int tick)
{
FILETIME LocalFileTime, FileTime;
HANDLE hFile;
int success;
char buf[1024];
fname_atow (name, buf, sizeof buf);
if ((hFile = CreateFile (buf, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
lasterror = GetLastError ();
return 0;
}
*(__int64 *) & LocalFileTime = (((__int64) (377 * 365 + 91 + days) * (__int64) 1440 + (__int64) minute) * (__int64) (60 * 50) + (__int64) tick) * (__int64) 200000;
if (!LocalFileTimeToFileTime (&LocalFileTime, &FileTime))
FileTime = LocalFileTime;
if (!(success = SetFileTime (hFile, &FileTime, &FileTime, &FileTime)))
lasterror = GetLastError ();
CloseHandle (hFile);
return success;
}
int posixemu_read (int hFile, char *ptr, int size)
{
DWORD actual;
if (!ReadFile ((HANDLE) hFile, ptr, size, &actual, NULL))
lasterror = GetLastError ();
return actual;
}
int posixemu_write (int hFile, char *ptr, int size)
{
DWORD actual;
if (!WriteFile ((HANDLE) hFile, ptr, size, &actual, NULL))
lasterror = GetLastError ();
return actual;
}
int posixemu_seek (int hFile, int pos, int type)
{
int result;
switch (type) {
case SEEK_SET:
type = FILE_BEGIN;
break;
case SEEK_CUR:
type = FILE_CURRENT;
break;
case SEEK_END:
type = FILE_END;
}
if ((result = SetFilePointer ((HANDLE) hFile, pos, NULL, type)) == ~0)
lasterror = GetLastError ();
return result;
}
int stdioemu_fread (char *buf, int l1, int l2, FILE * hFile)
{
return posixemu_read ((int) hFile, buf, l1 * l2);
}
int stdioemu_fwrite (char *buf, int l1, int l2, FILE * hFile)
{
return posixemu_write ((int) hFile, buf, l1 * l2);
}
int stdioemu_fseek (FILE * hFile, int pos, int type)
{
return posixemu_seek ((int) hFile, pos, type);
}
int stdioemu_ftell (FILE * hFile)
{
return SetFilePointer ((HANDLE) hFile, 0, 0, FILE_CURRENT);
}
int posixemu_stat (char *name, struct stat *statbuf)
{
char buf[1024];
DWORD attr;
HANDLE hFile;
FILETIME ft, lft;
fname_atow (name, buf, sizeof buf);
if ((attr = getattr (buf, &ft, &statbuf->st_size)) == ~0) {
lasterror = GetLastError ();
return -1;
} else {
statbuf->st_mode = (attr & FILE_ATTRIBUTE_READONLY) ? 5 : 0;
if (attr & FILE_ATTRIBUTE_ARCHIVE)
statbuf->st_mode |= 0x10;
if (attr & FILE_ATTRIBUTE_DIRECTORY)
statbuf->st_mode |= 0x100;
FileTimeToLocalFileTime (&ft, &lft);
statbuf->st_mtime = (*(__int64 *) & lft - ((__int64) (369 * 365 + 89) * (__int64) (24 * 60 * 60) * (__int64) 10000000)) / (__int64) 10000000;
}
return 0;
}
int posixemu_mkdir (char *name, int mode)
{
char buf[1024];
fname_atow (name, buf, sizeof buf);
if (CreateDirectory (buf, NULL))
return 0;
lasterror = GetLastError ();
return -1;
}
int posixemu_unlink (char *name)
{
char buf[1024];
fname_atow (name, buf, sizeof buf);
if (DeleteFile (buf))
return 0;
lasterror = GetLastError ();
return -1;
}
int posixemu_rmdir (char *name)
{
char buf[1024];
fname_atow (name, buf, sizeof buf);
if (RemoveDirectory (buf))
return 0;
lasterror = GetLastError ();
return -1;
}
int posixemu_rename (char *name1, char *name2)
{
char buf1[1024];
char buf2[1024];
fname_atow (name1, buf1, sizeof buf1);
fname_atow (name2, buf2, sizeof buf2);
if (MoveFile (name1, name2))
return 0;
lasterror = GetLastError ();
return -1;
}
int posixemu_chmod (char *name, int mode)
{
char buf[1024];
DWORD attr = FILE_ATTRIBUTE_NORMAL;
fname_atow (name, buf, sizeof buf);
if (mode & 1)
attr |= FILE_ATTRIBUTE_READONLY;
if (mode & 0x10)
attr |= FILE_ATTRIBUTE_ARCHIVE;
if (SetFileAttributes (buf, attr))
return 1;
lasterror = GetLastError ();
return 0;
}
void posixemu_tmpnam (char *name)
{
char buf[MAX_PATH];
GetTempPath (MAX_PATH, buf);
GetTempFileName (buf, "uae", 0, name);
}
/* pthread Win32 emulation */
void sem_init (HANDLE * event, int manual_reset, int initial_state)
{
*event = CreateEvent (NULL, manual_reset, initial_state, NULL);
}
void sem_wait (HANDLE * event)
{
WaitForSingleObject (*event, INFINITE);
}
void sem_post (HANDLE * event)
{
SetEvent (*event);
}
int sem_trywait (HANDLE * event)
{
return WaitForSingleObject (*event, 0) == WAIT_OBJECT_0;
}
/* Mega-klduge to prevent problems with Watcom's habit of passing
* arguments in registers... */
static HANDLE thread_sem;
static void *(*thread_startfunc) (void *);
#ifndef __GNUC__
static void * __stdcall thread_starter (void *arg)
#else
static void * thread_starter( void *arg )
#endif
{
void *(*func) (void *) = thread_startfunc;
SetEvent (thread_sem);
return (*func) (arg);
}
/* this creates high priority threads by default to speed up the file system (kludge, will be
* replaced by a set_penguin_priority() routine soon) */
int start_penguin (void *(*f) (void *), void *arg, DWORD * foo)
{
static int have_event = 0;
HANDLE hThread;
if (! have_event) {
thread_sem = CreateEvent (NULL, 0, 0, NULL);
have_event = 1;
}
thread_startfunc = f;
hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) thread_starter, arg, 0, foo);
SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST);
WaitForSingleObject (thread_sem, INFINITE);
}